﻿#include "DataWriter.h"
#include <QDir>
#include <QThread>


template QString DataWriter::translationRule<qint64>(QString rule, int row);
template QString DataWriter::translationRule<double>(QString rule, int row);
template qint64 DataWriter::getValueByRule<qint64>(QString rule, int row);
template double DataWriter::getValueByRule<double>(QString rule, int row);
template void DataWriter::writeValue<qint64>(qint64 value, int row, int col);
template void DataWriter::writeValue<double>(double value, int row, int col);
template void DataWriter::writeValue<QString>(QString value, int row, int col);


DataWriter::DataWriter(QObject *parent)
    : QObject{parent}
{}

DataWriter::DataWriter(AbstractSheet* sheet)
{
    if (this->sheet) {
        delete sheet;
    }
    this->sheet = (Worksheet*)sheet;
}


// 将第row行列的数据根据规则转换为计算字符串
template<typename T>
QString DataWriter::translationRule(QString rule, int row)
{
    QString res;
    int index = 0;
    rule = rule.replace(" ", "");
    do {
        if (rule[index] == ' ') continue;

        if (!isOperationSign(rule[index])) {

            int sign_pos = index + getFirstOperationSignPos(rule.mid(index, rule.length() - index));
            QString num_str = rule.mid(index, sign_pos - index);

            index = sign_pos - 1;
            if (std::is_integral<T>::value) {
                res += QString::number(readCell(row, num_str.toUInt()).toInt());
            } else if (std::is_floating_point<T>::value) {
                res += QString::number(readCell(row, num_str.toUInt()).toDouble());
            }
        } else {
            res += rule[index];
        }
    } while( ++index < rule.length() &&rule[index].toLatin1() != '\0');


    return res;
}


QVariant DataWriter::readCell(int row, int col)
{
    QVariant var;

    if (sheet) {
        QXlsx::Cell* cell = sheet->cellAt(row, col); // get cell pointer.
        if ( cell != NULL )
        {
            var = cell->readValue(); // read cell value (number(double), QDateTime, QString ...)
        }
    }

    return var;
}

// QStringList DataWriter::getSheetsName()
// {
//     QStringList resList;

//     if (doc && doc->load()) resList = doc->sheetNames();

//     return resList;
// }

// bool DataWriter::setActivateSheet(QString sheetName)
// {
//     if (doc && doc->load()) {
//         return doc->selectSheet(sheetName);
//     } else return false;
// }

// int DataWriter::getTotalRows()
// {
//     if (doc && doc->load()) {
//         return doc->dimension().rowCount();
//     } else return 0;
// }

void DataWriter::setParam(QString logDir, QJsonObject colObj, QHash<QString, QJsonObject> logFilters, QString logEndStr, quint16 start, quint16 count)
{
    m_LogDir = logDir;
    m_ColObj = colObj;
    m_LogFilters = logFilters;
    m_LogEndStr = logEndStr;
    m_Start = start;
    m_Count = count;
}

void DataWriter::run()
{
    // if (!readFile()) {
    //     qDebug()<< "excel file readed error!";
    //     return;
    // }
    QStringList colkeys = m_ColObj.keys();
    QStringList filterKeys = m_LogFilters.keys();

    QDir directory(m_LogDir);

    if (!directory.exists()) {
        qDebug() << "Log Directory does not exist.";
        return;
    }

    QFileInfoList fileList = directory.entryInfoList();

    // 逐行处理表格
    for (int row = m_Start; row <= m_Start + m_Count; ++row ) {
        // 遍历所有日志
        // qDebug()<<"start"<<row;
        bool line_finish_flag = false;
        for (auto const &fileInfo : std::as_const(fileList)) {
            if(fileInfo.isDir()) continue;
            LogReader tLR(fileInfo.absoluteFilePath());
            tLR.setCycleEndFlag(m_LogEndStr);  // 设置日志的结束标志

            // 判断该行是否已被填写数据
            bool nextLine = false;
            for (auto const &key : std::as_const(colkeys)) {
                if (!readCell(row, key.toUInt()).isNull() ||readCell(row, key.toUInt()).isValid()) {
                    nextLine = true;
                    break;
                }
            }
            // qDebug()<<nextLine;
            if (nextLine == true) continue;

            if (!tLR.readFile()) {
                qDebug()<<"log read error";
                continue;
            }

            // 处理日志
            while(1) {
                QString cycleStr = tLR.readNextCycle();   // 读取一个周期的日志数据
                if (cycleStr.isEmpty()) break;

                // 检查是否该周期是否满足筛选条件
                 bool filterFlag = false;        // 帅选条件判断结果
                for(auto const & key : std::as_const(filterKeys)) {
                    // 如果改行日志包含要提取和判断的变量，则进行处理
                    // qDebug()<<"Key----------"<<key;
                    if (!cycleStr.contains(key)) break;

                    QString lineFeatures = m_LogFilters[key]["LineFeatures"].toString();
                    if (!lineFeatures.isEmpty()) {

                        // 需要逐行处理
                        // 处理数据
                        QTextStream textStream(cycleStr.toUtf8());
                        while(!textStream.atEnd()) {
                            QString line = textStream.readLine();   // 读取一行
                            if (!line.contains(lineFeatures)) continue;     // 行未包含筛选特征，继续下一行
                            // qDebug()<<line;
                            // 根据过滤条件进行判断和提取
                            // 如果改行日志包含要提取和判断的变量，则进行处理
                            if (line.contains(key)) {
                                QString formatStr = m_LogFilters[key]["Format"].toString();   // 获取该变量在日志中写入的格式

                                // 根据提供的格式从日志中提取对应的变量字符串
                                QString tVarName = key;
                                tVarName = tVarName.replace("[", "\\[");
                                tVarName = tVarName.replace("]", "\\]");
                                tVarName = tVarName.replace("(", "\\(");
                                tVarName = tVarName.replace(")", "\\)");
                                QRegularExpression re(u8".*[,，\\s]+(" + tVarName + u8"\\s*=\\s*(\\(*" + replaceWithRegex(formatStr) + "\\)*)+)[,，]?\\s*\\w+.+");
                                QRegularExpressionMatch match = re.match(line);
                                if (match.hasMatch()) {
                                    QString varStr = match.captured(1);
                                    // qDebug()<< "matched:"<<varStr;
                                    // 根据变量格式获取变量匹配到的整型值
                                    QHash<QString, qint64> intHash = getValueListFromStrByFormat(varStr, formatStr);
                                    // qDebug()<<intHash;
                                    // 根据规则进行计算和判断
                                    QString ruleStr = m_LogFilters[key]["Rule"].toString();   // 获取计算规则字符串
                                    QList<QStringList> formulaList = getRules(ruleStr);    // 提取当前变量的判断公式列表
                                    // 遍历公式

                                    for (auto &formula : formulaList) {
                                        // 将计算规则两边的公式转化为整型值
                                        quint64 value_left, value_right;
                                        if (formula[0].contains("var")) {
                                            // 根据公式和获取的整型值列表获取公式左边的值
                                            QString value_str = translationByFormula(intHash, formula[0]);
                                            value_left = caculation<qint64>(value_str);
                                        } else {
                                            value_left = formula[0].toLongLong();
                                        }

                                        value_right = getValueByRule<qint64>(formula[1], row);

                                        // 根据不同的条件判断
                                        if (formula[2].contains(">")) {
                                            if (value_left > value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains("<")) {
                                            if (value_left < value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains(">=")) {
                                            if (value_left >= value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains("<=")) {
                                            if (value_left <= value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains("=")) {
                                            if (value_left == value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                    }

                                }
                            }
                            if (!filterFlag) break;  // 当前周期不满足，跳出该周期逐行循环

                        }


                    } else {

                        QString formatStr = m_LogFilters[key]["Format"].toString();   // 获取该变量在日志中写入的格式

                        // 根据提供的格式从日志中提取对应的变量字符串
                        QString tVarName = key;
                        tVarName = tVarName.replace("[", "\\[");
                        tVarName = tVarName.replace("]", "\\]");
                        tVarName = tVarName.replace("(", "\\(");
                        tVarName = tVarName.replace(")", "\\)");
                        QRegularExpression re(u8".*[,，\\s]+(" + tVarName + u8"\\s*=\\s*(\\(*" + replaceWithRegex(formatStr) + "\\)*)+)[,，]?\\s*\\w+.+");
                        QRegularExpressionMatch match = re.match(cycleStr);

                        if (match.hasMatch()) {
                            QString varStr = match.captured(1);
                            // qDebug()<< "matched:"<<varStr;
                            // 根据变量格式获取变量匹配到的整型值
                            QHash<QString, qint64> intHash = getValueListFromStrByFormat(varStr, formatStr);
                            // qDebug()<<intHash;
                            // 根据规则进行计算和判断
                            QString ruleStr = m_LogFilters[key]["Rule"].toString();   // 获取计算规则字符串
                            QList<QStringList> formulaList = getRules(ruleStr);    // 提取当前变量的判断公式列表
                            // 遍历公式
                            for (auto &formula : formulaList) {
                                // 将计算规则两边的公式转化为整型值
                                quint64 value_left, value_right;
                                if (formula[0].contains("var")) {
                                    // 根据公式和获取的整型值列表获取公式左边的值
                                    QString value_str = translationByFormula(intHash, formula[0]);
                                    value_left = caculation<qint64>(value_str);
                                } else {
                                    value_left = formula[0].toLongLong();
                                }

                                value_right = getValueByRule<qint64>(formula[1], row);

                                // 根据不同的条件判断
                                if (formula[2].contains(">")) {
                                    if (value_left > value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains("<")) {
                                    if (value_left < value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains(">=")) {
                                    if (value_left >= value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains("<=")) {
                                    if (value_left <= value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains("=")) {
                                    if (value_left == value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (!filterFlag) break;         // 有任一筛选条件不满足，跳出筛选条件循环

                }   // 筛选条件循环结束

                if (filterFlag) {
                    // 根据需要填写的变量从日志中获取内容
                    for (auto const &key : std::as_const(colkeys)) {
                        QJsonArray varArray = m_ColObj[key].toObject()["Variants"].toArray();
                        QStringList varList;
                        for (auto const &var : std::as_const(varArray)) {
                            QTextStream tTextStream(cycleStr.toUtf8());
                            while(!tTextStream.atEnd()) {
                                QString line = tTextStream.readLine();
                                if (!line.contains(var.toString())) continue;
                                QString str = getStringFromLineByVarName(line, var.toString());
                                varList.append(str);
                            }
                        }

                        QString dateTime = getDateTimeFromLog(cycleStr);

                        // qDebug()<< "write:"<<row << key.toUInt()<<varList;
                        mutex.lock();
                        writeValue<QString>(dateTime + " " + varList.join(""), row, key.toUInt());
                        mutex.unlock();
                    }
                    line_finish_flag = true;
                    break;
                }   // 写入Excel结束


            }   // 周期处理循环

            tLR.closeFile();
            if (line_finish_flag) break;
            // qDebug()<<u8"日志处理结束" << fileInfo.fileName()<< QThread::currentThreadId();

        }   // 文件处理循环
        // qDebug()<<"end"<<row;
        emit processedOneLine();
    }   // 行处理循环

    // doc->save();

    emit threadFinished();
}

void DataWriter::run1()
{
    // if (!readFile()) {
    //     qDebug()<< "excel file readed error!";
    //     return;
    // }
    QStringList colkeys = m_ColObj.keys();
    QStringList filterKeys = m_LogFilters.keys();

    QDir directory(m_LogDir);

    if (!directory.exists()) {
        qDebug() << "Log Directory does not exist.";
        return;
    }

    QFileInfoList fileList = directory.entryInfoList();

    // 逐行处理表格
    for (auto const &fileInfo : std::as_const(fileList)) {
        // 遍历所有日志
        // bool line_finish_flag = false;
        if(fileInfo.isDir()) continue;
        LogReader tLR(fileInfo.absoluteFilePath());
        tLR.setCycleEndFlag(m_LogEndStr);  // 设置日志的结束标志



        if (!tLR.readFile()) {
            qDebug()<<"log read error";
            continue;
        }

        // 处理日志
        while(1) {
            QString cycleStr = tLR.readNextCycle();   // 读取一个周期的日志数据
            if (cycleStr.isEmpty()) break;

            for (int row = m_Start; row <= m_Start + m_Count; ++row ) {

                // 判断该行是否已被填写数据
                bool nextLine = false;
                for (auto const &key : std::as_const(colkeys)) {
                    if (!readCell(row, key.toUInt()).isNull() ||readCell(row, key.toUInt()).isValid()) {
                        nextLine = true;
                        break;
                    }
                }

                if (nextLine == true) continue;

                // 检查是否该周期是否满足筛选条件
                bool filterFlag = false;        // 帅选条件判断结果
                for(auto const & key : std::as_const(filterKeys)) {
                    // 如果改行日志包含要提取和判断的变量，则进行处理
                    // qDebug()<<"Key----------"<<key;
                    if (!cycleStr.contains(key)) break;

                    QString lineFeatures = m_LogFilters[key]["LineFeatures"].toString();
                    if (!lineFeatures.isEmpty()) {

                        // 需要逐行处理
                        // 处理数据
                        QTextStream textStream(cycleStr.toUtf8());
                        while(!textStream.atEnd()) {
                            QString line = textStream.readLine();   // 读取一行
                            if (!line.contains(lineFeatures)) continue;     // 行未包含筛选特征，继续下一行
                            // qDebug()<<line;
                            // 根据过滤条件进行判断和提取
                            // 如果改行日志包含要提取和判断的变量，则进行处理
                            if (line.contains(key)) {
                                QString formatStr = m_LogFilters[key]["Format"].toString();   // 获取该变量在日志中写入的格式

                                // 根据提供的格式从日志中提取对应的变量字符串
                                QString tVarName = key;
                                tVarName = tVarName.replace("[", "\\[");
                                tVarName = tVarName.replace("]", "\\]");
                                tVarName = tVarName.replace("(", "\\(");
                                tVarName = tVarName.replace(")", "\\)");
                                QRegularExpression re(u8".*[,，\\s]+(" + tVarName + u8"\\s*=\\s*(\\(*" + replaceWithRegex(formatStr) + "\\)*)+)[,，]?\\s*\\w+.+");
                                QRegularExpressionMatch match = re.match(line);
                                if (match.hasMatch()) {
                                    QString varStr = match.captured(1);
                                    // qDebug()<< "matched:"<<varStr;
                                    // 根据变量格式获取变量匹配到的整型值
                                    QHash<QString, qint64> intHash = getValueListFromStrByFormat(varStr, formatStr);
                                    // qDebug()<<intHash;
                                    // 根据规则进行计算和判断
                                    QString ruleStr = m_LogFilters[key]["Rule"].toString();   // 获取计算规则字符串
                                    QList<QStringList> formulaList = getRules(ruleStr);    // 提取当前变量的判断公式列表
                                    // 遍历公式

                                    for (auto &formula : formulaList) {
                                        // 将计算规则两边的公式转化为整型值
                                        quint64 value_left, value_right;
                                        if (formula[0].contains("var")) {
                                            // 根据公式和获取的整型值列表获取公式左边的值
                                            QString value_str = translationByFormula(intHash, formula[0]);
                                            value_left = caculation<qint64>(value_str);
                                        } else {
                                            value_left = formula[0].toLongLong();
                                        }

                                        value_right = getValueByRule<qint64>(formula[1], row);

                                        // 根据不同的条件判断
                                        if (formula[2].contains(">")) {
                                            if (value_left > value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains("<")) {
                                            if (value_left < value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains(">=")) {
                                            if (value_left >= value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains("<=")) {
                                            if (value_left <= value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                        if (formula[2].contains("=")) {
                                            if (value_left == value_right) {
                                                filterFlag = true;
                                                continue;
                                            } else {
                                                filterFlag = false;
                                                break;
                                            }
                                        }
                                    }

                                }
                            }
                            if (!filterFlag) break;  // 当前周期不满足，跳出逐行循环

                        }


                    } else {

                        QString formatStr = m_LogFilters[key]["Format"].toString();   // 获取该变量在日志中写入的格式

                        // 根据提供的格式从日志中提取对应的变量字符串
                        QString tVarName = key;
                        tVarName = tVarName.replace("[", "\\[");
                        tVarName = tVarName.replace("]", "\\]");
                        tVarName = tVarName.replace("(", "\\(");
                        tVarName = tVarName.replace(")", "\\)");
                        QRegularExpression re(u8".*[,，\\s]+(" + tVarName + u8"\\s*=\\s*(\\(*" + replaceWithRegex(formatStr) + "\\)*)+)[,，]?\\s*\\w+.+");
                        QRegularExpressionMatch match = re.match(cycleStr);

                        if (match.hasMatch()) {
                            QString varStr = match.captured(1);
                            // qDebug()<< "matched:"<<varStr;
                            // 根据变量格式获取变量匹配到的整型值
                            QHash<QString, qint64> intHash = getValueListFromStrByFormat(varStr, formatStr);
                            // qDebug()<<intHash;
                            // 根据规则进行计算和判断
                            QString ruleStr = m_LogFilters[key]["Rule"].toString();   // 获取计算规则字符串
                            QList<QStringList> formulaList = getRules(ruleStr);    // 提取当前变量的判断公式列表
                            // 遍历公式
                            for (auto &formula : formulaList) {
                                // 将计算规则两边的公式转化为整型值
                                quint64 value_left, value_right;
                                if (formula[0].contains("var")) {
                                    // 根据公式和获取的整型值列表获取公式左边的值
                                    QString value_str = translationByFormula(intHash, formula[0]);
                                    value_left = caculation<qint64>(value_str);
                                } else {
                                    value_left = formula[0].toLongLong();
                                }

                                value_right = getValueByRule<qint64>(formula[1], row);

                                // 根据不同的条件判断
                                if (formula[2].contains(">")) {
                                    if (value_left > value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains("<")) {
                                    if (value_left < value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains(">=")) {
                                    if (value_left >= value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains("<=")) {
                                    if (value_left <= value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                                if (formula[2].contains("=")) {
                                    if (value_left == value_right) {
                                        filterFlag = true;
                                        continue;
                                    } else {
                                        filterFlag = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (!filterFlag) break;         // 有任一筛选条件不满足，跳出筛选条件循环

                }   // 筛选条件循环结束

                if (filterFlag) {
                    // 根据需要填写的变量从日志中获取内容
                    for (auto const &key : std::as_const(colkeys)) {
                        QJsonArray varArray = m_ColObj[key].toObject()["Variants"].toArray();
                        QStringList varList;
                        for (auto const &var : std::as_const(varArray)) {
                            QTextStream tTextStream(cycleStr.toUtf8());
                            while(!tTextStream.atEnd()) {
                                QString line = tTextStream.readLine();
                                if (!line.contains(var.toString())) continue;
                                QString str = getStringFromLineByVarName(line, var.toString());
                                varList.append(str);
                            }
                        }

                        QString dateTime = getDateTimeFromLog(cycleStr);

                        // qDebug()<< "write:"<<row << key.toUInt()<<varList;
                        // mutex.lock();
                        writeValue<QString>(dateTime + " " + varList.join(""), row, key.toUInt());
                        // mutex.unlock();
                    }
                }   // 写入Excel结束
            }

        }   // 周期处理循环
        tLR.closeFile();

        emit processedOneFile();
    }   // 文件处理循环

    // doc->save();

    emit threadFinished();
}



// bool DataWriter::readFile()
// {

//     if (!doc->load()) return false;

//     return true;
// }



template<typename T>
T DataWriter::getValueByRule(QString rule, int row)
{
    if (isAllDigits(rule)) {
        if (std::is_integral<T>::value) {
            return readCell(row, rule.toUInt()).toLongLong();
        } else if (std::is_floating_point<T>::value) {
            return readCell(row, rule.toUInt()).toDouble();
        }
    }
    T res;
    QString ruleStr = translationRule<T>(rule, row);
    res = caculation<T>(ruleStr);

    return res;
}


template<typename T>
void DataWriter::writeValue(T value, int row, int col) {

    sheet->write(row, col, QVariant(value));

}


